/**
 * 在源文件的开始定义包名，包名不必和文件夹路径一致：
 * 源文件可以放在任意位置（貌似不行）
 */
package com.example.tangjiangxu.kotlintest

import android.app.Activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import kotlinx.android.synthetic.main.activity_main.*
import java.io.File
import java.util.*

/**
 * Created by josan_tang on 5/25/17.
 */
class MainActivity : Activity() {

    var str:String = ""
    fun testFuncionExtension(){
        //所有类都可以调用
        showToast(this, "类扩展")
        //String类型可以调用
        str.mySelfMethod()
        //Activity类型可以调用
        getActivityParams()
    }

    //变量必须初始化
    //var str1:String
    //并且初始化不能为null
    //var str2:String = null
    //如果可以为null，则需要在类型后面增加?
    var str3:String? = null

    /**
     * 当使用一个可以为null的变量时，也需要对其进行null判断
     */
    fun test1() {
        if (str3 != null) {
            str3.toString()
        }
        //更简单的做法,在变量名后在安全访问操作符？
        str3?.toString()
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        btn_show.setOnClickListener {
            //启动登录Activity
            //创建一个伴生对象
            navigateTo(this)

        }
    }

    //创建一个伴生对象
    companion object {
        fun navigateTo(context: Context) {
            val intent = Intent(context, LoginActivity::class.java)
            context.startActivity(intent)
        }
    }


    fun testLambda() {
        var files:File
    }

    /**
     * 函数定义格式： fun 方法名(参数名：参数类型)：返回值类型｛｝
     * 不需要返回值时，写Unit
     */
    fun sum(a: Int, b: Int) : Int {
        return a + b
    }

    /**
     * 如果只有一个表达式，以及一个自推导型的返回值，可以简写成下面的样式
     */
    fun sum2(a: Int, b: Int) = a + b

    /**
     * 不需要返回值时，可以指定Unit类型，或者可以省略（当然是选择省略啰）
     */
    fun sum3(a: Int, b: Int): Unit {
        print(a + b)
    }

    /**
     * 定义局部常量
     * 格式：val 常量名：类型名 ＝ 初始化值
     */
    fun testVal() {
        val a :Int = 1
        val b = 1   //推导出Int型
        val c : Int    //局部常量可以只定义，不初始化，全局常量必须定义的时候初始化
    }

    /**
     * 定义局部变量
     * 格式：var 变量名 ＝ 初始化值
     */
    fun testVar() {
        var x = 5
        x += 1
    }

    //注释是和Java一样的
    //支持单行注释
    /**
     * 也支持块注释
     */

    /**
     * 使用字符串模版
     * 在字符串中可以直接使用${}来取值
     */
    fun testStrTemp(args: Array<String>) {
        if (args.size == 0) return

        print("First argument: ${args[0]}")
    }

    /**
     * 条件表达式
     */
    fun testConditionalOperator(a: Int, b: Int):Int {
        if (a > b)
            return a
        else
            return b
    }
    //可以简写成下面的形式
    fun testConditionalOperator2(a:Int, b:Int) = if(a>b) a else b

    /**
     * 返回一个Int类型的数，有可能返回null
     */
    fun parseInt(str : String) : Int?{
        return null
    }

    /**
     * 测试空安全
     * 当有可能出现空值时，必须明确指出该应用可为null
     */
    fun testNull(args : Array<String>) {
        if (args.size < 2) {
            print("Two integers expected!")
            return
        }

        //val x = parseInt(null)    //这里传null就会报错
        val x = parseInt(args[0])
        val y = parseInt(args[1])
        //直接使用x * y,会产生错误，因为它们中有可能有空值
        if (x != null && y != null) {
            print(x * y)
        }
    }

    /**
     * 使用is操作符检查一个表达式是某个类型当实例，相当于Java中当instanceof
     * 如果对不可变对局部变量或属性进行了类型检查，就不需要明确转型了
     */
    fun getStringLenght(obj:Any):Int?{
        if (obj is String) {
            //obj 将会在这个分支中自定转换为String类型
            return obj.length
        }
        //obj在种类检查外仍然是Any类型
        return 0
    }


    /**
     * 使用for循环，推荐使用in
     */
    fun testFor(args:Array<String>) {
        for (i in args) {
            print(i)
        }

        //或者

        for (i in args.indices)
            print(args[i])

        //使用while循环

        var i = 0
        while (i < args.size)
            print(args[i++])

    }

    /**
     * 使用When表达式，相当于switch
     */
    fun testWhen(obj: Any) {
        when(obj){
            1 -> print("one")
            "hello" -> print("Greeting")
            is Long -> print("Long")
            !is Long -> print("Not a Long")
            else -> print("unkown")
        }
    }


    /**
     * 使用in操作符，可以判断是否在或不在某个范围内
     */
    fun testRanges(x:Int, y:Int, args:Array<String>){
        if (x in 1..y-1)
            print("OK")

        if (x !in 0..args.lastIndex)
            print("Out")
    }

    /**
     * 用filter可以过滤，sortedBy完全排序，用map完成转换，forEach完成遍历
     */
    fun testFilter(names : Array<String>) {
        names
                .filter { it.startsWith("A") }
                .sortedBy { it }
                .map { it.toUpperCase() }
                .forEach { print(it) }
    }

    /**
     * 函数默认值
     */
    fun defualtArgs(a:Int=0,b:String="b") {

    }

    /**
     * 使用filter过滤
     */
    fun filterList(list:Array<Int>){
        var positivers = list.filter { it > 0 }
    }

    /**
     * 字符串插值
     */
    fun strInterpolation(str:String) {
        print("name:${str}")
    }

    /**
     * 用when进行实体类判断
     */
    fun beanCheck(x:Any){
        when(x){
            is Int-> print("Int")
            is Long-> print("Long")
            else -> print("Other")
        }
    }

    /**
     * 使用in来实现for循环
     */
    fun testRanges2() {
        for(i in 2..100) {
            print(i)
        }
    }

    /**
     * list和map的用法
     */
    fun testListAndMap(){
        //只读list和map
        var list = listOf("a","b","c");
        var map = mapOf("a" to 1, "b" to 2)
        //访问
        var mapValue = map["a"]
        //map["a"] = 3;    //这里会出错，应为map是只读对
    }

    /**
     * 懒加载
     */
    fun lazyLoad() {
        //val p:String by lazy {  }    //不知道为什么会报错
    }

    /**
     * 是null或者不是null的简写
     */
    fun sampleNullOrNotNull(){
        val files = File("test").listFiles();
        println(files?.size)
        //相当于
        /*if (files != null)
            print(files.size)*/
        println(files?.size?:"empty")
        //相当于
        /*if (files != null) {
            print(files.size)
        } else {
            print("empty")
        }*/
        //如果声明为空，执行某操作
        val data:Map<String, String>  = HashMap<String,String>();
        val email = data["email"]?:throw IllegalStateException("Email is missing!")

        //如果不为空执行操作
        var date:Int=8;
        date?.let {
            //如果不为空则执行，和?.有什么区别
        }

    }

    /**
     * try-catch的用法
     */
    fun testTryCatch() {
        val result = try {
            val a : Int = 5 / 0
        } catch (e:ArithmeticException) {
            throw IllegalStateException(e)
        }
        //处理result
    }

    /**
     * if的用法
     */
    fun testIf(param:Int) {
        val result = if(param == 1) {
            "one"
        } else if (param == 2) {
            "two"
        } else {
            "other"
        }
    }

    //只有一个表达式
    fun onlyOneExpression():Int = 42
    //可以和其他习惯用于组合成高效简介的代码，比如when
    fun transform(color:String):Int=when(color){
        "red"->0
        "green"->1
        "blue"->2
        else-> throw IllegalArgumentException("Invalid color param value")
    }


    /**
     * 利用with调用一个对象实例的多个方法
     */
    class Trutle{
        fun penDown(){}
        fun penup(){}
        fun trun(degrees:Double){}
        fun forward(pixels:Double){}
    }
    fun testWith(){
        val myTurtle = Trutle()
        with(myTurtle){
            penDown()
            for(i in 1..4) {
                forward(100.0)
                trun(90.0)
            }
            penup()
        }
    }

    /**
     * Kotlin文件中，可以直接调用Java代码
     * 代码中的User就是一个JavaBean
     * Kotlin中创建对象，不需要new
     */
    fun kotlinCallJava() {
        var user:User = User()
        user.age = 1
        user.name = "Josan"
    }



}
